2 ==============================================================================
4 This file is part of the JUCE library - "Jules' Utility Class Extensions"
5 Copyright 2004-11 by Raw Material Software Ltd.
7 ------------------------------------------------------------------------------
9 JUCE can be redistributed and/or modified under the terms of the GNU General
10 Public License (Version 2), as published by the Free Software Foundation.
11 A copy of the license is included in the JUCE distribution, or can be found
12 online at www.gnu.org/licenses.
14 JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18 ------------------------------------------------------------------------------
20 To release a closed-source product which uses JUCE, commercial licenses are
21 available: visit www.rawmaterialsoftware.com/juce for more information.
23 ==============================================================================
26 #include "../../jucer_Headers.h"
27 #include "../jucer_PaintRoutine.h"
28 #include "../../ui/jucer_PaintRoutineEditor.h"
29 #include "../../properties/jucer_PositionPropertyBase.h"
30 #include "jucer_ElementSiblingComponent.h"
31 #include "jucer_PaintElementUndoableAction.h"
34 //==============================================================================
35 PaintElement::PaintElement (PaintRoutine
* owner_
,
36 const String
& typeName_
)
42 originalAspectRatio (1.0)
44 setRepaintsOnMouseActivity (true);
46 position
.rect
.setWidth (100);
47 position
.rect
.setHeight (100);
49 setMinimumOnscreenAmounts (0, 0, 0, 0);
50 setSizeLimits (borderThickness
* 2 + 1, borderThickness
* 2 + 1, 8192, 8192);
52 addChildComponent (border
= new ResizableBorderComponent (this, this));
54 border
->setBorderThickness (BorderSize
<int> (borderThickness
));
57 owner
->getSelectedElements().addChangeListener (this);
59 selfChangeListenerList
.addChangeListener (this);
60 siblingComponentsChanged();
63 PaintElement::~PaintElement()
65 siblingComponents
.clear();
68 owner
->getSelectedElements().removeChangeListener (this);
74 //==============================================================================
75 void PaintElement::setInitialBounds (int parentWidth
, int parentHeight
)
77 RelativePositionedRectangle
pr (getPosition());
78 pr
.rect
.setX (parentWidth
/ 4 + Random::getSystemRandom().nextInt (parentWidth
/ 4) - parentWidth
/ 8);
79 pr
.rect
.setY (parentHeight
/ 3 + Random::getSystemRandom().nextInt (parentHeight
/ 4) - parentHeight
/ 8);
80 setPosition (pr
, false);
83 //==============================================================================
84 const RelativePositionedRectangle
& PaintElement::getPosition() const
89 class PaintElementMoveAction
: public PaintElementUndoableAction
<PaintElement
>
92 PaintElementMoveAction (PaintElement
* const element
, const RelativePositionedRectangle
& newState_
)
93 : PaintElementUndoableAction
<PaintElement
> (element
),
95 oldState (element
->getPosition())
102 getElement()->setPosition (newState
, false);
109 getElement()->setPosition (oldState
, false);
114 RelativePositionedRectangle newState
, oldState
;
117 void PaintElement::setPosition (const RelativePositionedRectangle
& newPosition
, const bool undoable
)
119 if (position
!= newPosition
)
123 perform (new PaintElementMoveAction (this, newPosition
),
124 "Move " + getTypeName());
128 position
= newPosition
;
136 //==============================================================================
137 const Rectangle
<int> PaintElement::getCurrentBounds (const Rectangle
<int>& parentArea
) const
139 return position
.getRectangle (parentArea
, getDocument()->getComponentLayout());
142 void PaintElement::setCurrentBounds (const Rectangle
<int>& newBounds
,
143 const Rectangle
<int>& parentArea
,
146 RelativePositionedRectangle
pr (position
);
147 pr
.updateFrom (newBounds
.getX() - parentArea
.getX(),
148 newBounds
.getY() - parentArea
.getY(),
149 jmax (1, newBounds
.getWidth()),
150 jmax (1, newBounds
.getHeight()),
151 Rectangle
<int> (0, 0, parentArea
.getWidth(), parentArea
.getHeight()),
152 getDocument()->getComponentLayout());
154 setPosition (pr
, undoable
);
156 updateBounds (parentArea
);
159 void PaintElement::updateBounds (const Rectangle
<int>& parentArea
)
161 if (! parentArea
.isEmpty())
163 setBounds (getCurrentBounds (parentArea
)
164 .expanded (borderThickness
,
167 for (int i
= siblingComponents
.size(); --i
>= 0;)
168 siblingComponents
.getUnchecked(i
)->updatePosition();
172 //==============================================================================
173 class ElementPositionProperty
: public PositionPropertyBase
176 //==============================================================================
177 ElementPositionProperty (PaintElement
* element_
,
179 ComponentPositionDimension dimension_
)
180 : PositionPropertyBase (element_
, name
, dimension_
, true, false,
181 element_
->getDocument()->getComponentLayout()),
184 element_
->getDocument()->addChangeListener (this);
187 ~ElementPositionProperty()
189 element
->getDocument()->removeChangeListener (this);
192 //==============================================================================
193 void setPosition (const RelativePositionedRectangle
& newPos
)
195 element
->setPosition (newPos
, true);
198 const RelativePositionedRectangle
getPosition() const
200 return element
->getPosition();
204 PaintElement
* const element
;
207 //==============================================================================
208 void PaintElement::getEditableProperties (Array
<PropertyComponent
*>& properties
)
210 properties
.add (new ElementPositionProperty (this, "x", PositionPropertyBase::componentX
));
211 properties
.add (new ElementPositionProperty (this, "y", PositionPropertyBase::componentY
));
212 properties
.add (new ElementPositionProperty (this, "width", PositionPropertyBase::componentWidth
));
213 properties
.add (new ElementPositionProperty (this, "height", PositionPropertyBase::componentHeight
));
216 //==============================================================================
217 JucerDocument
* PaintElement::getDocument() const
219 return owner
->getDocument();
222 void PaintElement::changed()
228 bool PaintElement::perform (UndoableAction
* action
, const String
& actionName
)
230 return owner
->perform (action
, actionName
);
233 void PaintElement::parentHierarchyChanged()
235 updateSiblingComps();
238 //==============================================================================
239 void PaintElement::drawExtraEditorGraphics (Graphics
& g
, const Rectangle
<int>& relativeTo
)
243 void PaintElement::paint (Graphics
& g
)
245 Rectangle
<int> area (((PaintRoutineEditor
*) getParentComponent())->getComponentArea());
248 g
.setOrigin (area
.getX() - getX(), area
.getY() - getY());
249 area
.setPosition (0, 0);
252 g
.reduceClipRegion (0, 0, area
.getWidth(), area
.getHeight());
254 draw (g
, getDocument()->getComponentLayout(), area
);
258 drawExtraEditorGraphics (g
, area
);
263 const BorderSize
<int> borderSize (border
->getBorderThickness());
265 drawResizableBorder (g
, getWidth(), getHeight(), borderSize
,
266 (isMouseOverOrDragging() || border
->isMouseOverOrDragging()));
268 else if (isMouseOverOrDragging())
270 drawMouseOverCorners (g
, getWidth(), getHeight());
274 void PaintElement::resized()
276 border
->setBounds (0, 0, getWidth(), getHeight());
279 void PaintElement::mouseDown (const MouseEvent
& e
)
285 owner
->getSelectedPoints().deselectAll();
286 mouseDownSelectStatus
= owner
->getSelectedElements().addToSelectionOnMouseDown (this, e
.mods
);
289 if (e
.mods
.isPopupMenu())
292 return; // this may be deleted now..
296 void PaintElement::mouseDrag (const MouseEvent
& e
)
298 if (! e
.mods
.isPopupMenu())
300 jassert (dynamic_cast <PaintRoutineEditor
*> (getParentComponent()) != 0);
301 const Rectangle
<int> area (((PaintRoutineEditor
*) getParentComponent())->getComponentArea());
303 if (selected
&& ! dragging
)
305 dragging
= ! e
.mouseWasClicked();
308 owner
->startDragging (area
);
312 owner
->dragSelectedComps (e
.getDistanceFromDragStartX(),
313 e
.getDistanceFromDragStartY(),
318 void PaintElement::mouseUp (const MouseEvent
& e
)
321 owner
->endDragging();
324 owner
->getSelectedElements().addToSelectionOnMouseUp (this, e
.mods
, dragging
, mouseDownSelectStatus
);
327 void PaintElement::resizeStart()
330 originalAspectRatio
= getWidth() / (double) getHeight();
332 originalAspectRatio
= 1.0;
335 void PaintElement::resizeEnd()
339 void PaintElement::checkBounds (Rectangle
<int>& bounds
,
340 const Rectangle
<int>& previousBounds
,
341 const Rectangle
<int>& limits
,
342 const bool isStretchingTop
,
343 const bool isStretchingLeft
,
344 const bool isStretchingBottom
,
345 const bool isStretchingRight
)
347 if (ModifierKeys::getCurrentModifiers().isShiftDown())
348 setFixedAspectRatio (originalAspectRatio
);
350 setFixedAspectRatio (0.0);
352 ComponentBoundsConstrainer::checkBounds (bounds
, previousBounds
, limits
, isStretchingTop
, isStretchingLeft
, isStretchingBottom
, isStretchingRight
);
354 JucerDocument
* document
= getDocument();
356 if (document
!= 0 && document
->isSnapActive (true))
358 jassert (getParentComponent() != 0);
359 const Rectangle
<int> area (((PaintRoutineEditor
*) getParentComponent())->getComponentArea());
361 int x
= bounds
.getX();
362 int y
= bounds
.getY();
363 int w
= bounds
.getWidth();
364 int h
= bounds
.getHeight();
366 x
+= borderThickness
- area
.getX();
367 y
+= borderThickness
- area
.getY();
368 w
-= borderThickness
* 2;
369 h
-= borderThickness
* 2;
374 if (isStretchingRight
)
375 right
= document
->snapPosition (right
);
377 if (isStretchingBottom
)
378 bottom
= document
->snapPosition (bottom
);
380 if (isStretchingLeft
)
381 x
= document
->snapPosition (x
);
384 y
= document
->snapPosition (y
);
386 w
= (right
- x
) + borderThickness
* 2;
387 h
= (bottom
- y
) + borderThickness
* 2;
388 x
-= borderThickness
- area
.getX();
389 y
-= borderThickness
- area
.getY();
391 bounds
= Rectangle
<int> (x
, y
, w
, h
);
395 void PaintElement::applyBoundsToComponent (Component
* component
, const Rectangle
<int>& bounds
)
397 if (getBounds() != bounds
)
399 getDocument()->getUndoManager().undoCurrentTransactionOnly();
401 jassert (dynamic_cast <PaintRoutineEditor
*> (getParentComponent()) != 0);
403 setCurrentBounds (bounds
.expanded (-borderThickness
, -borderThickness
),
404 ((PaintRoutineEditor
*) getParentComponent())->getComponentArea(),
409 const Rectangle
<int> PaintElement::getCurrentAbsoluteBounds() const
411 jassert (dynamic_cast <PaintRoutineEditor
*> (getParentComponent()) != 0);
412 const Rectangle
<int> area (((PaintRoutineEditor
*) getParentComponent())->getComponentArea());
414 return position
.getRectangle (area
, getDocument()->getComponentLayout());
417 void PaintElement::getCurrentAbsoluteBoundsDouble (double& x
, double& y
, double& w
, double& h
) const
419 jassert (dynamic_cast <PaintRoutineEditor
*> (getParentComponent()) != 0);
420 const Rectangle
<int> area (((PaintRoutineEditor
*) getParentComponent())->getComponentArea());
422 position
.getRectangleDouble (x
, y
, w
, h
, area
, getDocument()->getComponentLayout());
425 void PaintElement::changeListenerCallback (ChangeBroadcaster
*)
427 const bool nowSelected
= owner
!= 0 && owner
->getSelectedElements().isSelected (this);
429 if (selected
!= nowSelected
)
431 selected
= nowSelected
;
432 border
->setVisible (nowSelected
);
435 selectionChanged (nowSelected
);
438 updateSiblingComps();
441 void PaintElement::selectionChanged (const bool isSelected
)
445 void PaintElement::createSiblingComponents()
449 void PaintElement::siblingComponentsChanged()
451 siblingComponents
.clear();
452 selfChangeListenerList
.sendChangeMessage();
455 void PaintElement::updateSiblingComps()
457 if (selected
&& getParentComponent() != 0 && owner
->getSelectedElements().getNumSelected() == 1)
459 if (siblingComponents
.size() == 0)
460 createSiblingComponents();
462 for (int i
= siblingComponents
.size(); --i
>= 0;)
463 siblingComponents
.getUnchecked(i
)->updatePosition();
467 siblingComponents
.clear();
472 void PaintElement::showPopupMenu()
476 m
.addCommandItem (commandManager
, CommandIDs::toFront
);
477 m
.addCommandItem (commandManager
, CommandIDs::toBack
);
479 m
.addCommandItem (commandManager
, StandardApplicationCommandIDs::cut
);
480 m
.addCommandItem (commandManager
, StandardApplicationCommandIDs::copy
);
481 m
.addCommandItem (commandManager
, StandardApplicationCommandIDs::paste
);
482 m
.addCommandItem (commandManager
, StandardApplicationCommandIDs::del
);